<template><div><p>本文档最新版为 <a href="https://learnku.com/docs/laravel/10.x" target="_blank" rel="noopener noreferrer">10.x</a>，旧版本可能放弃维护，推荐阅读最新版！</p>
<h2 id="邮件认证" tabindex="-1"><a class="header-anchor" href="#邮件认证"><span>邮件认证</span></a></h2>
<ul>
<li><a href="#introduction">介绍</a>
<ul>
<li><a href="#model-preparation">准备模型</a></li>
<li><a href="#database-preparation">准备数据库</a></li>
</ul>
</li>
<li><a href="#verification-routing">路由</a>
<ul>
<li><a href="#the-email-verification-notice">邮件验证通知</a></li>
<li><a href="#the-email-verification-handler">邮件验证处理</a></li>
<li><a href="#resending-the-verification-email">重新发送验证邮件</a></li>
<li><a href="#protecting-routes">保护路由</a></li>
</ul>
</li>
<li><a href="#customization">自定义</a></li>
<li><a href="#events">事件</a></li>
</ul>
<h2 id="介绍" tabindex="-1"><a class="header-anchor" href="#介绍"><span>介绍</span></a></h2>
<p>很多 Web 应用会要求用户在使用之前进行 Email 地址验证。Laravel 不会强迫你在每个应用中手动重复实现该特性，而是提供了方便的内置服务来发送和校验电子邮件的验证请求。</p>
<blockquote>
<p>注意<br>
想快速上手吗？你可以在全新的应用中安装 <a href="https://learnku.com/docs/laravel/11.x/starter-kits" target="_blank" rel="noopener noreferrer">Laravel 应用入门套件</a>。入门套件将帮助你搭建整个身份验证系统，包括电子邮件验证支持。</p>
</blockquote>
<h3 id="准备模型" tabindex="-1"><a class="header-anchor" href="#准备模型"><span>准备模型</span></a></h3>
<p>在开始之前，需要检查你的 <code v-pre>App\Models\User</code> 模型是否实现了 <code v-pre>Illuminate\Contracts\Auth\MustVerifyEmail</code> 契约：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token php language-php"><span class="token delimiter important">&lt;?php</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">namespace</span> <span class="token package">App<span class="token punctuation">\</span>Models</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Contracts<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>MustVerifyEmail</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>User</span> <span class="token keyword">as</span> Authenticatable<span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Notifications<span class="token punctuation">\</span>Notifiable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token keyword">class</span> <span class="token class-name-definition class-name">User</span> <span class="token keyword">extends</span> <span class="token class-name">Authenticatable</span> <span class="token keyword">implements</span> <span class="token class-name">MustVerifyEmail</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">use</span> <span class="token package">Notifiable</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>一旦这一接口被添加到模型中，新注册的用户将自动收到一封包含电子邮件验证链接的电子邮件。这是无缝发生的，因为 Laravel 自动为 <code v-pre>Illuminate\Auth\Events\Registered</code> 事件注册了 <code v-pre>Illuminate\Auth\Listeners\SendEmailVerificationNotification</code> <a href="https://learnku.com/docs/laravel/11.x/events" target="_blank" rel="noopener noreferrer">监听器</a>。</p>
<p>如果你没有在应用中使用<a href="https://learnku.com/docs/laravel/11.x/starter-kits" target="_blank" rel="noopener noreferrer">入门套件</a>而是手动实现的注册，你需要确保在用户注册成功后手动分发 <code v-pre>Illuminate\Auth\Events\Registered</code> 事件：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Events<span class="token punctuation">\</span>Registered</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token function">event</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Registered</span><span class="token punctuation">(</span><span class="token variable">$user</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="数据库准备" tabindex="-1"><a class="header-anchor" href="#数据库准备"><span>数据库准备</span></a></h3>
<p>接下来，<code v-pre>users</code> 表中必须有一个 <code v-pre>email_verified_at</code> 字段，用以保存用户邮箱验证日期和时间。通常，这个字段在 Laravel 自带的 <code v-pre>0001_01_01_000000_create_users_table.php</code> 数据库迁移文件已经默认包含了。</p>
<h2 id="路由" tabindex="-1"><a class="header-anchor" href="#路由"><span>路由</span></a></h2>
<p>为了实现邮件认证，需要定义三个路由。首先，需要一个路由来向用户显示通知，通知用户在注册后，应该点击 Laravel 发送给他们的验证邮件中的链接。</p>
<p>其次，需要一个路由来处理用户点击邮件中验证链接时发来的请求。</p>
<p>第三，如果用户没有收到验证邮件，则需要一路由来重新发送验证邮件。</p>
<h3 id="邮箱验证通知" tabindex="-1"><a class="header-anchor" href="#邮箱验证通知"><span>邮箱验证通知</span></a></h3>
<p>如前所述，应该定义一条路由，该路由将返回一个视图，引导用户点击注册后 Laravel 发送给他们邮件中的验证链接。当用户尝试访问网站的其它页面而没有先完成邮箱验证时，将向用户显示此视图。请注意，只要你的 <code v-pre>App\Models\User</code> 模型实现了 <code v-pre>MustVerifyEmail</code> 接口，就会自动将该链接发邮件给用户：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/email/verify'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">view</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'auth.verify-email'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'verification.notice'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>返回邮件验证通知的路由应该命名为 <code v-pre>verification.notice</code>。将这个路由分配这个命名很重要，因为如果用户邮箱验证未通过，<a href="#protecting-routes">Laravel 自带的 <code v-pre>verified</code> 中间件</a>将会自动重定向到该路由名上。</p>
<blockquote>
<p>注意<br>
手动实现邮箱验证过程时，你需要自己定义验证通知视图。如果你希望包含所有必要的身份认证和验证视图，请查看 <a href="https://learnku.com/docs/laravel/11.x/starter-kits" target="_blank" rel="noopener noreferrer">Laravel 应用入门套件</a>。</p>
</blockquote>
<h3 id="邮件验证处理" tabindex="-1"><a class="header-anchor" href="#邮件验证处理"><span>邮件验证处理</span></a></h3>
<p>接下来，我们需要定义一个路由，它将在用户点击邮件验证链接时处理生成的请求。该路由应该命名为 <code v-pre>verification.verify</code>，并且为其分配 <code v-pre>auth</code> 和 <code v-pre>signed</code> 中间件：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Foundation<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>EmailVerificationRequest</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/email/verify/{id}/{hash}'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">EmailVerificationRequest</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">fulfill</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">redirect</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/home'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'signed'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'verification.verify'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>在继续之前，让我们仔细看一下这个路由。首先，你会注意到我们使用的是 <code v-pre>EmailVerificationRequest</code> 请求类型，而不是通常的 <code v-pre>Illuminate\Http\Request</code> 实例。 <code v-pre>EmailVerificationRequest</code> 是 Laravel 中包含的<a href="https://learnku.com/docs/laravel/11.x/validation#form-request-validation" target="_blank" rel="noopener noreferrer">表单请求</a>。此请求将自动处理验证请求的 <code v-pre>id</code> 和 <code v-pre>hash</code> 参数。</p>
<p>接下来，我们可以直接在请求上调用 <code v-pre>fulfill</code> 方法。该方法将在身份认证过的用户上调用 <code v-pre>markEmailAsVerified</code> 方法，并会触发 <code v-pre>Illuminate\Auth\Events\Verified</code> 事件。通过 <code v-pre>Illuminate\Foundation\Auth\User</code> 基类，<code v-pre>markEmailAsVerified</code> 方法可用于默认的 <code v-pre>App\Models\User</code> 模型。验证用户的电子邮件地址后，你可以将其重定向到任意位置。</p>
<h3 id="重发验证邮件" tabindex="-1"><a class="header-anchor" href="#重发验证邮件"><span>重发验证邮件</span></a></h3>
<p>有时候，用户可能输错了电子邮件地址或者不小心删除了验证邮件。为了解决这种问题，你可能会想定义一个路由允许用户请求重新发送验证邮件。你可以在<a href="#the-email-verification-notice">验证通知视图</a>中放置一个简单的表单来实现此功能：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Http<span class="token punctuation">\</span>Request</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">post</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/email/verification-notification'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token class-name type-declaration">Request</span> <span class="token variable">$request</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token variable">$request</span><span class="token operator">-></span><span class="token function">user</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">sendEmailVerificationNotification</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line">    <span class="token keyword">return</span> <span class="token function">back</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">with</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'message'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'Verification link sent!'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'throttle:6,1'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">name</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'verification.send'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="保护路由" tabindex="-1"><a class="header-anchor" href="#保护路由"><span>保护路由</span></a></h3>
<p><a href="https://learnku.com/docs/laravel/11.x/middleware" target="_blank" rel="noopener noreferrer">路由中间件</a>可用作只允许认证过的用户访问给定路由。Laravel 自带了一个 <code v-pre>verified</code> <a href="https://learnku.com/docs/laravel/11.x/middleware#middleware-alias" target="_blank" rel="noopener noreferrer">中间件别名</a>，它是<code v-pre>Illuminate\Auth\Middleware\EnsureEmailIsVerified</code> 中间件类的别名。由于该别名已经由 Laraval 自动注册，所以你只需将中间件附加到路由定义即可。通常，此中间件与 <code v-pre>auth</code> 中间件配对使用：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token class-name static-context">Route</span><span class="token operator">::</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'/profile'</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// Only verified users may access this route...</span></span>
<span class="line"><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token operator">-></span><span class="token function">middleware</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string single-quoted-string">'auth'</span><span class="token punctuation">,</span> <span class="token string single-quoted-string">'verified'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果未经验证的用户尝试访问已经分配了该中间件的路由，将会被自动重定向到 <code v-pre>verification.notice</code> <a href="https://learnku.com/docs/laravel/11.x/routing#named-routes" target="_blank" rel="noopener noreferrer">命名路由</a>。</p>
<h2 id="自定义" tabindex="-1"><a class="header-anchor" href="#自定义"><span>自定义</span></a></h2>
<h4 id="自定义验证邮件" tabindex="-1"><a class="header-anchor" href="#自定义验证邮件"><span>自定义验证邮件</span></a></h4>
<p>尽管默认的邮件验证通知可以满足大部分应用的需求，Laravel 还是允许你自定义验证邮件消息的构建。</p>
<p>要开始自定义验证邮件，请将一个闭包传递给 <code v-pre>Illuminate\Auth\Notifications\VerifyEmail</code> 通知提供的 <code v-pre>toMailUsing</code> 方法。该闭包接收 notifiable 模型实例，该模型实例接收通知以及用户必须访问以验证邮箱地址的签名邮箱验证 URL。该闭包返回一个 <code v-pre>Illuminate\Notifications\Messages\MailMessage</code> 实例。通常，你应该在应用的 <code v-pre>AppServiceProvider</code> 类的 <code v-pre>boot</code> 方法中调用 <code v-pre>toMailUsing</code> 方法：</p>
<div class="language-php line-numbers-mode" data-highlighter="prismjs" data-ext="php" data-title="php"><pre v-pre class="language-php"><code><span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Auth<span class="token punctuation">\</span>Notifications<span class="token punctuation">\</span>VerifyEmail</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token keyword">use</span> <span class="token package">Illuminate<span class="token punctuation">\</span>Notifications<span class="token punctuation">\</span>Messages<span class="token punctuation">\</span>MailMessage</span><span class="token punctuation">;</span></span>
<span class="line"></span>
<span class="line"><span class="token doc-comment comment">/**</span>
<span class="line"> * Bootstrap any application services.</span>
<span class="line"> */</span></span>
<span class="line"><span class="token keyword">public</span> <span class="token keyword">function</span> <span class="token function-definition function">boot</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword return-type">void</span></span>
<span class="line"><span class="token punctuation">{</span></span>
<span class="line">    <span class="token comment">// ...</span></span>
<span class="line"></span>
<span class="line">    <span class="token class-name static-context">VerifyEmail</span><span class="token operator">::</span><span class="token function">toMailUsing</span><span class="token punctuation">(</span><span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token keyword type-hint">object</span> <span class="token variable">$notifiable</span><span class="token punctuation">,</span> <span class="token keyword type-hint">string</span> <span class="token variable">$url</span><span class="token punctuation">)</span> <span class="token punctuation">{</span></span>
<span class="line">        <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">MailMessage</span><span class="token punctuation">)</span></span>
<span class="line">            <span class="token operator">-></span><span class="token function">subject</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Verify Email Address'</span><span class="token punctuation">)</span></span>
<span class="line">            <span class="token operator">-></span><span class="token function">line</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Click the button below to verify your email address.'</span><span class="token punctuation">)</span></span>
<span class="line">            <span class="token operator">-></span><span class="token function">action</span><span class="token punctuation">(</span><span class="token string single-quoted-string">'Verify Email Address'</span><span class="token punctuation">,</span> <span class="token variable">$url</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line">    <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></span>
<span class="line"><span class="token punctuation">}</span></span>
<span class="line"></span></code></pre>
<div class="line-numbers" aria-hidden="true" style="counter-reset:line-number 0"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote>
<p>注意<br>
要了解更多关于邮件通知的内容，请参考<a href="https://learnku.com/docs/laravel/11.x/notifications#mail-notifications" target="_blank" rel="noopener noreferrer">邮件通知文档</a>。</p>
</blockquote>
<h2 id="时间" tabindex="-1"><a class="header-anchor" href="#时间"><span>时间</span></a></h2>
<p>使用 <a href="https://learnku.com/docs/laravel/11.x/starter-kits" target="_blank" rel="noopener noreferrer">Laravel 入门套件</a>时，Laravel 在电子邮件验证过程中会派发<code v-pre>Illuminate\Auth\Events\Verified</code> <a href="https://learnku.com/docs/laravel/11.x/events" target="_blank" rel="noopener noreferrer">事件</a> 。如果你想让你的应用手动处理邮箱验证，你可以在验证完成后手动分发这些事件。</p>
<blockquote>
<p>本译文仅用于学习和交流目的，转载请务必注明文章译者、出处、和本文链接<br>
我们的翻译工作遵照 <a href="https://learnku.com/docs/guide/cc4.0/6589" target="_blank" rel="noopener noreferrer">CC 协议</a>，如果我们的工作有侵犯到您的权益，请及时联系我们。</p>
</blockquote>
<hr>
<blockquote>
<p>原文地址：<a href="https://learnku.com/docs/laravel/11.x/verificationmd/16692" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/11.x/ve...</a></p>
<p>译文地址：<a href="https://learnku.com/docs/laravel/11.x/verificationmd/16692" target="_blank" rel="noopener noreferrer">https://learnku.com/docs/laravel/11.x/ve...</a></p>
</blockquote>
</div></template>


